"""
项目管理系统 - FastAPI主应用入口
"""

from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import JSONResponse
from contextlib import asynccontextmanager
from pydantic import ValidationError
import time
import logging
import os
import uuid

from app.core.config import settings
from app.core.database import init_database, close_database
from app.core.response import error_response, ErrorTypes, ErrorMessages
from app.api.api import api_router


# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    # 启动时执行
    logger.info("正在启动项目管理系统...")
    await init_database()
    logger.info("数据库连接已建立")
    
    yield
    
    # 关闭时执行
    logger.info("正在关闭项目管理系统...")
    await close_database()
    logger.info("数据库连接已关闭")


# 创建FastAPI应用实例
app = FastAPI(
    title=settings.APP_NAME,
    version=settings.APP_VERSION,
    description="基于6A工作流程的企业级项目管理平台",
    openapi_url=f"{settings.API_V1_STR}/openapi.json",
    docs_url=f"{settings.API_V1_STR}/docs",
    redoc_url=f"{settings.API_V1_STR}/redoc",
    lifespan=lifespan
)

# 添加CORS中间件 - 必须在其他中间件之前添加
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.allowed_origins,  # 使用属性方法，自动包含开发环境地址
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["*"],
    max_age=86400,  # 预检请求缓存时间（秒）
)

# 添加可信主机中间件 - 开发环境允许所有主机
# 注意：在生产环境中应该配置具体的域名
if not settings.DEBUG:
    app.add_middleware(
        TrustedHostMiddleware,
        allowed_hosts=settings.ALLOWED_HOSTS
    )


@app.middleware("http")
async def add_request_id_and_process_time(request: Request, call_next):
    """添加请求ID和处理时间头"""
    # 记录CORS相关信息
    origin = request.headers.get("origin")
    if request.method == "OPTIONS":
        logger.info(f"收到OPTIONS预检请求: {request.url}")
        logger.info(f"Origin: {origin}")
        logger.info(f"允许的源: {settings.allowed_origins}")
        logger.info(f"请求头: {dict(request.headers)}")
    
    # 生成请求ID
    request_id = str(uuid.uuid4())
    request.state.request_id = request_id
    
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    
    # 记录OPTIONS响应信息
    if request.method == "OPTIONS":
        logger.info(f"OPTIONS响应状态码: {response.status_code}")
        logger.info(f"Access-Control-Allow-Origin: {response.headers.get('Access-Control-Allow-Origin', 'Not Set')}")
        logger.info(f"响应头: {dict(response.headers)}")
    
    # 添加响应头
    response.headers["X-Request-ID"] = request_id
    response.headers["X-Process-Time"] = str(process_time)
    
    # CORS 调试信息（仅开发环境）
    if settings.DEBUG and origin:
        response.headers["X-CORS-Debug-Origin"] = origin
        response.headers["X-CORS-Debug-Allowed"] = ",".join(settings.allowed_origins)
    
    return response


@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    """HTTP异常处理器"""
    request_id = getattr(request.state, 'request_id', None)
    logger.warning(f"HTTP异常 [{request_id}]: {exc.status_code} - {exc.detail}")
    
    return JSONResponse(
        status_code=exc.status_code,
        content=error_response(
            error_type=ErrorTypes.HTTP_ERROR,
            message=exc.detail,
            code=exc.status_code,
            request_id=request_id
        )
    )


@app.exception_handler(ValidationError)
async def validation_exception_handler(request: Request, exc: ValidationError):
    """参数验证异常处理器"""
    request_id = getattr(request.state, 'request_id', None)
    logger.warning(f"参数验证异常 [{request_id}]: {exc}")
    
    # 格式化验证错误信息
    errors = []
    for error in exc.errors():
        field = '.'.join(str(x) for x in error['loc'])
        errors.append(f"{field}: {error['msg']}")
    
    return JSONResponse(
        status_code=422,
        content=error_response(
            error_type=ErrorTypes.VALIDATION_ERROR,
            message=ErrorMessages.VALIDATION_FAILED,
            code=422,
            details=errors,
            request_id=request_id
        )
    )


@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    """全局异常处理器"""
    request_id = getattr(request.state, 'request_id', None)
    trace_id = str(uuid.uuid4())
    
    logger.error(f"全局异常 [{request_id}] [{trace_id}]: {exc}", exc_info=True)
    
    return JSONResponse(
        status_code=500,
        content=error_response(
            error_type=ErrorTypes.INTERNAL_ERROR,
            message=ErrorMessages.INTERNAL_ERROR,
            code=500,
            details=str(exc) if settings.DEBUG else "服务暂时不可用，请稍后重试",
            trace_id=trace_id,
            request_id=request_id
        )
    )


# 健康检查端点
@app.get("/health")
async def health_check(request: Request):
    """健康检查"""
    from app.core.response import success_response
    
    request_id = getattr(request.state, 'request_id', None)
    
    return JSONResponse(
        content=success_response(
            data={
                "status": "healthy",
                "app_name": settings.APP_NAME,
                "version": settings.APP_VERSION,
                "timestamp": time.time()
            },
            message="系统运行正常",
            request_id=request_id
        )
    )


# 根路径重定向
@app.get("/")
async def root(request: Request):
    """根路径"""
    from app.core.response import success_response
    
    request_id = getattr(request.state, 'request_id', None)
    
    return JSONResponse(
        content=success_response(
            data={
                "message": f"欢迎使用{settings.APP_NAME}",
                "version": settings.APP_VERSION,
                "docs_url": f"{settings.API_V1_STR}/docs",
                "redoc_url": f"{settings.API_V1_STR}/redoc"
            },
            message="欢迎访问项目管理系统API",
            request_id=request_id
        )
    )


# Settings API 重定向优化
@app.get("/api/v1/settings")
async def settings_redirect(request: Request):
    """Settings API 重定向 - 提供API使用指南"""
    from app.core.response import success_response
    
    request_id = getattr(request.state, 'request_id', None)
    
    return JSONResponse(
        content=success_response(
            data={
                "message": "系统设置API需要认证访问",
                "authentication_required": True,
                "available_endpoints": {
                    "get_settings": "GET /api/v1/settings/ (需要认证)",
                    "update_general": "PUT /api/v1/settings/general (需要认证)",
                    "update_security": "PUT /api/v1/settings/security (需要认证)",
                    "update_notification": "PUT /api/v1/settings/notification (需要认证)",
                    "update_system": "PUT /api/v1/settings/system (需要认证)",
                    "update_backup": "PUT /api/v1/settings/backup (需要认证)",
                    "test_email": "POST /api/v1/settings/test-email (需要认证)",
                    "backup_history": "GET /api/v1/settings/backup/history (需要认证)",
                    "create_backup": "POST /api/v1/settings/backup/create (需要认证)",
                    "delete_backup": "DELETE /api/v1/settings/backup/{backup_id} (需要认证)"
                },
                "docs_url": f"{settings.API_V1_STR}/docs#/settings",
                "login_url": "/api/v1/auth/login",
                "required_permission": "system:manage"
            },
            message="系统设置API使用指南",
            request_id=request_id
        )
    )


# 配置静态文件服务
uploads_dir = os.path.join(os.path.dirname(__file__), settings.UPLOAD_DIR)
os.makedirs(uploads_dir, exist_ok=True)
app.mount("/uploads", StaticFiles(directory=uploads_dir), name="uploads")

# 包含API路由
app.include_router(api_router, prefix=settings.API_V1_STR)


if __name__ == "__main__":
    import uvicorn
    
    uvicorn.run(
        "main:app",
        host=settings.BACKEND_HOST,
        port=settings.BACKEND_PORT,
        reload=settings.DEBUG,
        log_level="info"
    )